﻿namespace Okazuki.TepcoUsageApi.Client
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Net;
    using System.Runtime.Serialization.Json;

    /// <summary>
    /// http://tepco-usage-api.appspot.com/で提供されているAPI用インターフェース。
    /// エラー時はコールバックの引数にnullがわたってきます。
    /// </summary>
    public interface ITepcoCapacityClient
    {
        /// <summary>
        /// 最新の電力使用状況を返します
        /// </summary>
        /// <param name="callback">コールバック</param>
        void GetLatest(Action<TepcoStatus> callback);

        /// <summary>
        /// 指定された日時の電力使用状況を返します。
        /// </summary>
        /// <param name="year">年</param>
        /// <param name="month">月</param>
        /// <param name="day">日</param>
        /// <param name="hour">時</param>
        /// <param name="callback">コールバック</param>
        void GetStatusByDateTime(int year, int month, int day, int hour, Action<TepcoStatus> callback);

        /// <summary>
        /// 指定された日の毎時の電力使用状況を、リストとして返します。
        /// </summary>
        /// <param name="year">年</param>
        /// <param name="month">月</param>
        /// <param name="day">日</param>
        /// <param name="callback">コールバック</param>
        void GetStatysByDate(int year, int month, int day, Action<IList<TepcoStatus>> callback);

        /// <summary>
        /// 指定された月の毎日毎時の電力使用状況を、リストとして返します
        /// </summary>
        /// <param name="year">年</param>
        /// <param name="month">月</param>
        /// <param name="callback">コールバック</param>
        void GetStatusByMonth(int year, int month, Action<IList<TepcoStatus>> callback);
    }

    /// <summary>
    /// http://tepco-usage-api.appspot.com/で提供されているAPIの呼び出し用クラス
    /// </summary>
    public class TepcoCapacityClient : ITepcoCapacityClient
    {
        private static readonly string BaseApiUrl = "http://tepco-usage-api.appspot.com/";

        private static readonly string LatestApiUrl = BaseApiUrl + "latest.json";

        private static readonly string ByDateTimeApiUrl = BaseApiUrl + "{0}/{1}/{2}/{3}.json";

        private static readonly string ByDateApiUrl = BaseApiUrl + "{0}/{1}/{2}.json";

        private static readonly string ByMonthApiUrl = BaseApiUrl + "{0}/{1}.json";


        public void GetLatest(Action<TepcoStatus> callback)
        {
            this.CallApi<TepcoStatus>(
                LatestApiUrl,
                callback);
        }

        public void GetStatusByDateTime(int year, int month, int day, int hour, Action<TepcoStatus> callback)
        {
            this.CallApi<TepcoStatus>(
                string.Format(ByDateTimeApiUrl, year, month, day, hour),
                callback);
        }

        public void GetStatysByDate(int year, int month, int day, Action<IList<TepcoStatus>> callback)
        {
            this.CallApi<IList<TepcoStatus>>(
                string.Format(ByDateApiUrl, year, month, day),
                callback);
        }

        public void GetStatusByMonth(int year, int month, Action<IList<TepcoStatus>> callback)
        {
            this.CallApi<IList<TepcoStatus>>(
                string.Format(ByMonthApiUrl, year, month),
                callback);
        }

        private void CallApi<T>(string uri, Action<T> callback)
            where T : class
        {
            Debug.WriteLine(uri);
            var req = WebRequest.Create(uri);
            req.BeginGetResponse(
                this.Callback<T>,
                new Tuple<WebRequest, Action<T>>(req, callback));
        }

        private void Callback<T>(IAsyncResult ar)
            where T : class
        {
            var status = ar.AsyncState as Tuple<WebRequest, Action<T>>;
            try
            {
                var req = status.Item1;
                var response = req.EndGetResponse(ar);
                var s = new DataContractJsonSerializer(typeof(T));
                var tepco = s.ReadObject(response.GetResponseStream()) as T;
                status.Item2(tepco);
            }
            catch
            {
                // とりあえず握り潰し
                status.Item2(null);
            }
        }
    }

}
